package com.schoolvisitors.service;

import com.alibaba.fastjson2.JSONArray;
import com.schoolvisitors.entity.Admin;
import com.schoolvisitors.entity.Instrument;
import com.schoolvisitors.entity.Role;
import com.schoolvisitors.entity.Room;
import com.schoolvisitors.enums.PermissionEnum;
import com.schoolvisitors.enums.ResourceTypeEnum;
import com.schoolvisitors.enums.RoomTypeEnum;
import com.schoolvisitors.repository.AdminRepository;
import com.schoolvisitors.repository.ResourcesRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class AdminPermissionService {

    private final ResourcesRepository resourcesRepository;
    private final AdminRepository adminRepository;

    public AdminPermissionService(ResourcesRepository resourcesRepository,
                                  AdminRepository adminRepository) {
        this.resourcesRepository = resourcesRepository;
        this.adminRepository = adminRepository;
    }

    public boolean hasRoomPermission(Admin admin, Room room) {
        if (admin == null || room == null) return false;

        Role role = admin.getRole();
        if (role == null) return false;

        if (hasPermission(admin, PermissionEnum.SYSTEM_ADMIN)) {
            return true;
        }

        if (room.getType() == RoomTypeEnum.LAB && !hasPermission(admin, PermissionEnum.LAB_REVIEW)) {
            return false;
        }

        if (room.getType() == RoomTypeEnum.MEETING && !hasPermission(admin, PermissionEnum.MEETING_REVIEW)) {
            return false;
        }

        Long roleId = role.getId();
        Long floorId = room.getFloor() != null ? room.getFloor().getId() : null;
        Long roomId = room.getId();

        if (floorId != null && resourcesRepository.existsByRoleIdAndTypeAndResourceIndex(roleId, ResourceTypeEnum.FLOOR, floorId)) {
            return true;
        }

        return resourcesRepository.existsByRoleIdAndTypeAndResourceIndex(roleId, ResourceTypeEnum.ROOM, roomId);
    }

    public boolean hasInstrumentPermission(Admin admin, Instrument instrument) {
        if (admin == null || instrument == null) return false;

        Role role = admin.getRole();
        if (role == null) return false;

        if (hasPermission(admin, PermissionEnum.SYSTEM_ADMIN)) {
            return true;
        }

        if (!hasPermission(admin, PermissionEnum.INSTRUMENT_REVIEW)) {
            return false;
        }

        Long instrumentId = instrument.getId();
        Long floorId = instrument.getRoom() != null && instrument.getRoom().getFloor() != null
                ? instrument.getRoom().getFloor().getId()
                : null;

        // 如果有楼层权限，直接通过
        if (floorId != null && resourcesRepository.existsByRoleIdAndTypeAndResourceIndex(
                role.getId(), ResourceTypeEnum.FLOOR, floorId)) {
            return true;
        }

        // 否则判断是否有仪器权限
        return resourcesRepository.existsByRoleIdAndTypeAndResourceIndex(
                role.getId(),
                ResourceTypeEnum.INSTRUMENT,
                instrumentId
        );
    }

    public boolean hasPermission(Admin admin, PermissionEnum permission) {
        if (admin == null || admin.getRole() == null) return false;
        JSONArray permissionArray = JSONArray.parseArray(admin.getRole().getPermissions());
        return permissionArray.contains(permission.name());
    }

    private boolean hasResourceAccess(Admin admin, PermissionEnum requiredPermission, ResourceTypeEnum resourceType, Long resourceId) {
        if (admin == null || admin.getRole() == null) return false;

        // 系统管理员直接通过
        if (hasPermission(admin, PermissionEnum.SYSTEM_ADMIN)) return true;

        // 必须有指定权限
        if (!hasPermission(admin, requiredPermission)) return false;

        // 判断资源权限
        return resourcesRepository.existsByRoleIdAndTypeAndResourceIndex(admin.getRole().getId(), resourceType, resourceId);
    }

    public List<Admin> getReviewers(Room room, PermissionEnum permission) {
        if (room == null || permission == null) return new ArrayList<>();

        List<Admin> allAdmins = adminRepository.findAllByReviewerAndDeleteFalse(true);
        List<Admin> result = new ArrayList<>();

        Long floorId = room.getFloor() != null ? room.getFloor().getId() : null;
        Long roomId = room.getId();

        for (Admin admin : allAdmins) {
            // 优先判断楼层权限
            if (floorId != null && hasResourceAccess(admin, permission, ResourceTypeEnum.FLOOR, floorId)) {
                log.info("floorId: {}  admin: {}", floorId, admin.getUsername());
                result.add(admin);
                continue;
            }

            // 再判断房间权限
            if (hasResourceAccess(admin, permission, ResourceTypeEnum.ROOM, roomId)) {
                log.info("roomId: {}  admin: {}", roomId, admin.getUsername());
                result.add(admin);
            }
        }
        return result;
    }
    public List<Admin> getInstrumentPermissionReviewers() {
        List<Admin> allAdmins = adminRepository.findAllByReviewerAndDeleteFalse(true);
        List<Admin> result = new ArrayList<>();

        for (Admin admin : allAdmins) {
            if (hasPermission(admin, PermissionEnum.INSTRUMENT_REVIEW)) {
                result.add(admin);
            }
        }

        return result;
    }

    public List<Admin> getReviewers(Instrument instrument, PermissionEnum permission) {
        if (instrument == null || permission == null) return new ArrayList<>();

        List<Admin> allAdmins = adminRepository.findAllByReviewerAndDeleteFalse(true);
        List<Admin> result = new ArrayList<>();

        Long instrumentId = instrument.getId();
        Long floorId = instrument.getRoom() != null && instrument.getRoom().getFloor() != null
                ? instrument.getRoom().getFloor().getId()
                : null;

        for (Admin admin : allAdmins) {
            // 先判断楼层权限
            if (floorId != null && hasResourceAccess(admin, permission, ResourceTypeEnum.FLOOR, floorId)) {
                result.add(admin);
                continue;
            }

            // 再判断仪器权限
            if (hasResourceAccess(admin, permission, ResourceTypeEnum.INSTRUMENT, instrumentId)) {
                log.info("instrumentId: {}  admin: {}", instrumentId, admin.getUsername());
                result.add(admin);
            }
        }

        return result;
    }

}
